package net.csdn.business.mirror.utils;


import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.scheduling.support.CronSequenceGenerator;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.Temporal;
import java.util.Calendar;
import java.util.Date;

@Slf4j
public class TimeUtil {

    /**
     * 默认日期格式
     */
    public static final String DEFAULT_FORMAT = "yyyy-MM-dd HH:mm:ss";

    public static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss SSS";

    public static final String SHIP_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss.SSS";

    public static final String DEFAULT_DATE_ONLY_FORMAT = "yyyy-MM-dd";

    public static final String DEFAULT_DATE_FORMAT_CN = "yyyy年MM月dd日";

    public static final String TIME_FORMAT_WITHOUT_SECONDS = "yyyy-MM-dd HH:mm";

    public static final String TIME_FORMAT_WITH_HOUR_MIN = "HH:mm";

    public static final String TIME_MONTH_DAY_FORMAT = "MM.dd";

    public static final String TIME_FORMAT = "yyyyMMdd";

    public final static DateTimeFormatter DEFAULT_TIME_FORMAT = DateTimeFormatter.ofPattern(DEFAULT_FORMAT);

    public final static ZoneId DEFAULT_ZONE = ZoneId.of("Asia/Shanghai");

    /**
     * 把当前时间格式化成yyyy-MM-dd HH:mm:ss
     *
     * @return String
     */
    public static String date(Date date) {
        return date(date, DEFAULT_FORMAT);
    }

    public static String date(Date date, String timeFormat) {
        if (date == null) {
            return null;
        }
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(timeFormat);
        return date.toInstant().atZone(DEFAULT_ZONE).format(dateTimeFormatter);
    }

    /**
     * 获取时间java8时间
     *
     * @param date
     * @return
     */
    public static LocalDateTime getLocalDateTime(Date date) {
        Instant instant = Instant.now();
        if (date != null) {
            instant = date.toInstant();
        }
        return LocalDateTime.ofInstant(instant, DEFAULT_ZONE);
    }


    /**
     * 获取时间戳时间
     *
     * @param timestamp
     * @return
     */
    public static LocalDateTime getDateTimeOfTimestamp(Long timestamp) {
        if (timestamp == null || timestamp == 0) {
            return LocalDateTime.now();
        }
        Instant instant = Instant.ofEpochMilli(timestamp);
        return LocalDateTime.ofInstant(instant, DEFAULT_ZONE);
    }

    /**
     * 获取时间戳时间
     *
     * @param timestamp
     * @return
     */
    public static String getDateTimeOfTimestampString(Long timestamp) {
        if (timestamp == null || timestamp == 0) {
            return "";
        }
        Instant instant = Instant.ofEpochMilli(timestamp);
        return date(new Date(instant.toEpochMilli()));
    }

    /**
     * 获取两个时间间隔的天数
     *
     * @param former 前者
     * @param latter 后者
     * @return
     */
    public static Long getDaysBetweenTime(Temporal former, Temporal latter) {
        Duration duration = Duration.between(former, latter);
        return duration.toDays();
    }


    public static int getDiscrepantDays(Date dateStart, Date dateEnd) {
        return (int) ((dateEnd.getTime() - dateStart.getTime()) / 1000 / 60 / 60 / 24);
    }

    /**
     * 距离某天days天后的时间
     *
     * @param date
     * @param days
     * @return
     */
    public static Date afterDays(Date date, long days) {
        Instant instant = date.toInstant();
        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, DEFAULT_ZONE);
        LocalDateTime afterLocalDateTime = localDateTime.plusDays(days);
        return Date.from(afterLocalDateTime.atZone(DEFAULT_ZONE).toInstant());
    }

    public static Date afterMins(Date date, long mins) {
        Instant instant = date.toInstant();
        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, DEFAULT_ZONE);
        LocalDateTime afterLocalDateTime = localDateTime.plusMinutes(mins);
        return Date.from(afterLocalDateTime.atZone(DEFAULT_ZONE).toInstant());
    }

    /**
     * 两个date合成一个
     * 第一个取年月日
     * 第二个取时分秒
     */
    public static Date newDate(Date d1, Date d2) {
        return newDate(d1, d2, 0);
    }

    public static Date newDate(Date d1, Date d2, Integer days) {
        Instant instant1 = d1.toInstant();
        LocalDateTime localDateTime1 = LocalDateTime.ofInstant(instant1, DEFAULT_ZONE);
        localDateTime1 = localDateTime1.plusDays(days);
        LocalDate localDate = LocalDate.of(localDateTime1.getYear(), localDateTime1.getMonthValue(), localDateTime1.getDayOfMonth());
        Instant instant2 = d2.toInstant();
        LocalDateTime localDateTime2 = LocalDateTime.ofInstant(instant2, DEFAULT_ZONE);
        LocalTime localTime = LocalTime.of(localDateTime2.getHour(), localDateTime2.getMinute(), localDateTime2.getSecond());
        LocalDateTime localDateTime = LocalDateTime.of(localDate, localTime);
        return Date.from(localDateTime.atZone(DEFAULT_ZONE).toInstant());
    }

    /**
     * 获取时间time相关时间
     *
     * @param time
     * @param days
     * @param hours
     * @param minutes
     * @param seconds
     * @return
     */
    public static Date getTime(Date time, long days, long hours, long minutes, long seconds) {
        Instant instant = time.toInstant();
        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, DEFAULT_ZONE);
        LocalDateTime result;
        seconds += ((days * 24 + hours) * 60 + minutes) * 60;
        result = localDateTime.plusSeconds(seconds);
        return Date.from(result.atZone(DEFAULT_ZONE).toInstant());
    }

    /**
     * 获取明日此时时间
     *
     * @return
     */
    public static Date getThisTimeTomorrow() {
        return getTime(Calendar.getInstance().getTime(), 1, 0, 0, 0);
    }

    /**
     * 获取时间time相关时间
     *
     * @param time
     * @param days
     * @param hours
     * @param minutes
     * @param seconds
     * @return
     */
    public static LocalDateTime getLocalDateTime(LocalDateTime localDateTime, long days, long hours, long minutes, long seconds) {
        seconds += ((days * 24 + hours) * 60 + minutes) * 60;
        return localDateTime.plusSeconds(seconds);
    }

    /**
     * 根据事件字符串获取时间
     *
     * @param timeStr 时间字符串
     * @param format  时间格式
     * @return
     */
    public static Date getTime(String timeStr, String format) {
        if (timeStr.length() == 10) {
            DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(format);
            LocalDate localDate = LocalDate.parse(timeStr, dateTimeFormatter);
            return Date.from(localDate.atStartOfDay(DEFAULT_ZONE).toInstant());
        } else {
            DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(format);
            LocalDateTime localDateTime = LocalDateTime.parse(timeStr, dateTimeFormatter);
            return Date.from(localDateTime.atZone(DEFAULT_ZONE).toInstant());
        }
    }

    /**
     * 根据事件字符串获取时间  默认时间格式yyyy-MM-dd HH:mm:ss
     *
     * @param timeStr 时间字符串
     * @return
     */
    public static Date getTime(String timeStr) {
        if (StringUtils.isBlank(timeStr)) {
            return null;
        }
        String format = DEFAULT_FORMAT;
        if (timeStr.length() == 10) {
            format = DEFAULT_DATE_ONLY_FORMAT;
        }
        return getTime(timeStr, format);
    }

    /**
     * 获取今日零点
     *
     * @return
     */
    public static Date getTodayZero() {
        LocalDate date = LocalDate.now();
        LocalTime zero = LocalTime.MIN;
        LocalDateTime dateTime = LocalDateTime.of(date, zero);
        return Date.from(dateTime.atZone(DEFAULT_ZONE).toInstant());
    }

    /**
     * 获取当前时间零时
     *
     * @param date
     * @return
     */
    public static Date getDateZero(Date date) {
        LocalDate localDate = getLocalDateTime(date).toLocalDate();
        LocalTime zero = LocalTime.MIN;
        LocalDateTime dateTime = LocalDateTime.of(localDate, zero);
        return Date.from(dateTime.atZone(DEFAULT_ZONE).toInstant());
    }

    /**
     * 获取明日 零点
     *
     * @return
     */
    public static Date getTomorrowZero() {
        LocalDate today = LocalDate.now();
        LocalDate tomorrow = today.plusDays(1);
        LocalTime zero = LocalTime.MIN;
        LocalDateTime dateTime = LocalDateTime.of(tomorrow, zero);
        return Date.from(dateTime.atZone(DEFAULT_ZONE).toInstant());
    }

    /**
     * 获取明日 零点
     *
     * @return
     */
    public static LocalDateTime getLocalDateTimeTomorrowZero() {
        LocalDate today = LocalDate.now();
        LocalDate tomorrow = today.plusDays(1);
        LocalTime zero = LocalTime.MIN;
        return LocalDateTime.of(tomorrow, zero);
    }

    /**
     * 清楚毫秒和秒
     *
     * @param date
     * @return
     */
    public static Date cleanSecond(Date date) {
        if (date == null) {
            return null;
        }
        LocalDateTime dateTime = LocalDateTime.ofInstant(date.toInstant(), DEFAULT_ZONE);
        dateTime = dateTime.minusNanos(dateTime.getNano());
        dateTime = dateTime.minusSeconds(dateTime.getSecond());
        return Date.from(dateTime.atZone(DEFAULT_ZONE).toInstant());
    }

    /**
     * 获取模板消息时间
     *
     * @param couponGroup
     * @return
     */
    public static String getTemplateValidTime(Date[] couponGroup) {
        String start = TimeUtil.date(couponGroup[0], TimeUtil.TIME_FORMAT_WITHOUT_SECONDS);
        String end = TimeUtil.date(couponGroup[1], TimeUtil.TIME_FORMAT_WITHOUT_SECONDS);
        return start + "至" + end;
    }

    /**
     * 获取明天
     *
     * @return
     */
    public static LocalDate tomorrow() {
        return LocalDate.now().plusDays(1L);
    }

    public static String format(LocalDateTime localDateTime) {
        return format(localDateTime, DEFAULT_FORMAT);
    }

    public static String format(LocalDateTime localDateTime, String timeFormat) {
        if (localDateTime == null) {
            return null;
        }
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(timeFormat);
        return dateTimeFormatter.format(localDateTime);
    }

    public static Duration getCronDuration(String cron){
        CronSequenceGenerator generator = new CronSequenceGenerator(cron);
        Date nextExecution = generator.next(new Date());
        Date nextToNextExecution = generator.next(nextExecution);
        return Duration.between(nextExecution.toInstant(), nextToNextExecution.toInstant());
    }

}
